/**
 * Copyright (c) 2008, Andrew Carter
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are 
 * permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list of 
 * conditions and the following disclaimer. Redistributions in binary form must reproduce 
 * the above copyright notice, this list of conditions and the following disclaimer in 
 * the documentation and/or other materials provided with the distribution. Neither the 
 * name of Andrew Carter nor the names of contributors may be used to endorse or promote 
 * products derived from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.acarter.jmejtree;

import java.util.ArrayList;
import java.util.Vector;

import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import com.jme.scene.Node;
import com.jme.scene.Spatial;

/**
 * 
 * @author Andrew Carter
 */
public class JMEJTreeNodeModel implements TreeModel {

	/**	 */
	private Node rootNode = null;

	private Vector<TreeModelListener> listeners;

	/**
	 * Returns the root of the tree. Returns null only if the tree has no nodes.
	 * @param rootNode 
	 */
	public JMEJTreeNodeModel(Node rootNode) {

		this.rootNode = rootNode;
		listeners = new Vector<TreeModelListener>();
	}

	/**
	 * Returns the child of parent at index index in the parent's child array.
	 * parent must be a node previously obtained from this data source. This
	 * should not return null if index is a valid index for parent (that is
	 * index >= 0 && index < getChildCount(parent)).
	 */
	public Object getChild(Object parent, int index) {

		// Get an actual child node
		if (parent instanceof Node) {
			
			if ((index >= 0) && (index < getChildCount(parent)))
				return ((Node) parent).getChild(index);
		}
		
		return null;
	}

	/**
	 * Returns the number of children of parent. Returns 0 if the node is a leaf
	 * or if it has no children. parent must be a node previously obtained from
	 * this data source.
	 */
	public int getChildCount(Object parent) {

		if (parent instanceof Node)
			return ((Node) parent).getQuantity();

		return 0;
	}

	/**
	 * Returns the index of child in parent. If either parent or child is null,
	 * returns -1. If either parent or child don't belong to this tree model,
	 * returns -1.
	 */
	public int getIndexOfChild(Object parent, Object child) {

		if ((parent != null) && (child != null)) {

			if ((parent instanceof Node) && (child instanceof Node))
					return ((Node)parent).getChildIndex((Spatial) child);
		}
		
		return -1;
	}

	/**
	 * 
	 * @param child
	 * @return
	 */
	public Object getParent(Object child) {

		if (child instanceof Node)
			return ((Node) child).getParent();

		return null;
	}

	/**
	 * 
	 * @param object
	 * @return
	 */
	public TreePath getPathToRoot(Object object) {

		TreePath path = new TreePath(rootNode);

		ArrayList<Object> list = new ArrayList<Object>();

		list.add(0, object);

		while ((object = getParent(object)) != null) {

			if (object.equals(rootNode))
				break;

			list.add(0, object);
		}

		for (Object child : list)
			path = path.pathByAddingChild(child);

		return path;
	}

	/**
	 * Returns the root of the tree. Returns null only if the tree has no nodes.
	 */
	public Object getRoot() {

		return rootNode;
	}

	/**
	 * Returns true if node is a leaf. It is possible for this method to return
	 * false even if node has no children. A directory in a filesystem, for
	 * example, may contain no files; the node representing the directory is not
	 * a leaf, but it also has no children.
	 */
	public boolean isLeaf(Object object) {

		return (object instanceof Spatial) ? false : true;
	}

	/**
	 * Adds a listener for the TreeModelEvent posted after the tree changes.
	 */
	public void addTreeModelListener(TreeModelListener l) {

		listeners.add(l);
	}

	/**
	 * Removes a listener previously added with addTreeModelListener.
	 */
	public void removeTreeModelListener(TreeModelListener l) {

		listeners.remove(l);
	}

	/**
	 * 
	 * @param e
	 */
	public void fireTreeNodesChanged(TreeModelEvent e) {

		for (TreeModelListener l : listeners)
			l.treeNodesChanged(e);
	}

	/**
	 * 
	 * @param e
	 */
	public void fireTreeNodesInserted(TreeModelEvent e) {

		for (TreeModelListener l : listeners)
			l.treeNodesInserted(e);
	}

	/**
	 * 
	 * @param e
	 */
	public void fireTreeNodesRemoved(TreeModelEvent e) {

		for (TreeModelListener l : listeners)
			l.treeNodesRemoved(e);
	}

	/**
	 * 
	 * @param e
	 */
	public void fireTreeStructureChanged(TreeModelEvent e) {

		for (TreeModelListener l : listeners)
			l.treeStructureChanged(e);
	}

	/**
	 * Messaged when the user has altered the value for the item identified by
	 * path to newValue. If newValue signifies a truly new value the model
	 * should post a treeNodesChanged event.
	 */
	public void valueForPathChanged(TreePath path, Object newValue) {

	}
}
